home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / GameKit / gamekit-1 / GKStage.m < prev    next >
Text File  |  1995-06-12  |  7KB  |  229 lines

  1.  
  2. #import <gamekit/gamekit.h>
  3.  
  4. @interface GKStage(private)
  5. - _add:adds remove:removes with:theList; // helper for -doAddsAndRemoves
  6. @end
  7.  
  8. @implementation GKStage
  9.  
  10. - init
  11. {
  12.     id ret = [super init];
  13.     int i;
  14.     for (i=0; i<=GK_ACTOR_TYPES; i++) {
  15.         actors[i] = [[List alloc] init];
  16.         addActors[i] = [[List alloc] init];
  17.         removeActors[i] = [[List alloc] init];
  18.     }
  19.     collisionGroups = [[List alloc] init];
  20.     addCollisionGroups = [[List alloc] init];
  21.     removeCollisionGroups = [[List alloc] init];
  22.     stageManager = nil;
  23.     return ret;
  24. }
  25.  
  26. - makeDirtPileForBuffer:(int)anInt
  27. {    // you can use anInt to tweak each DirtPile differently to get better speed
  28.     if (!anInt) return nil; // no DirtPile at level zero...
  29.     return [[[DirtPile alloc] init] setAllDirty];
  30. }
  31.  
  32. - setBufferType:(int)anInt to:aBuffer
  33. {
  34.     if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
  35.     drawingBuffers[anInt] = aBuffer;
  36.     if (!anInt) return self;    // no dirtpile #0...
  37.     if (!dirtPiles[anInt])
  38.         dirtPiles[anInt] = [self makeDirtPileForBuffer:anInt];
  39.     return self;
  40. }
  41.  
  42. - dirtPileType:(int)anInt
  43. {
  44.     if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
  45.     return dirtPiles[anInt];
  46. }
  47.  
  48. - bufferType:(int)anInt
  49. {
  50.     if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
  51.     return drawingBuffers[anInt];
  52. }
  53.  
  54. - setStageManager:aManager { stageManager = aManager; return self; }
  55. - stageManager { return stageManager; }
  56.  
  57. - actorListForType:(int)type
  58. {
  59.     return actors[type];
  60. }
  61.  
  62. - addActor:anActor ofType:(int)type
  63. {    // hold on to it; we can't add while we're in the middle of a frame
  64.     // since it may affect the List object during a sweep of its contents
  65.     if ((type >= 0) && (type <= GK_ACTOR_TYPES))
  66.         [addActors[type] addObject:anActor];
  67.     return self;
  68. }
  69.  
  70. - removeActor:anActor ofType:(int)type
  71. {    // hold on to it; we can't remove while we're in the middle of a frame
  72.     // since it may affect the List object during a sweep of its contents
  73.     if ((type >= 0) && (type <= GK_ACTOR_TYPES))
  74.         [removeActors[type] addObject:anActor];
  75.     return self;
  76. }
  77.  
  78. - addCollisionGroup:aGroup
  79. {
  80.     [addCollisionGroups addObject:aGroup];
  81.     return self;
  82. }
  83.  
  84. - removeCollisionGroup:aGroup
  85. {
  86.     [removeCollisionGroups addObject:aGroup];
  87.     return self;
  88. }
  89.  
  90. - collisionGroups { return collisionGroups; }
  91. - findCollisionGroupWithTag:(int)anInt;
  92. {
  93.     int i;
  94.     for (i=0; i<[collisionGroups count]; i++) {
  95.         id group = [collisionGroups objectAt:i];
  96.         if ([group tag] == anInt) return group;
  97.     }
  98.     return nil;
  99. }
  100.  
  101. - _add:adds remove:removes with:theList level:(int)level
  102. {
  103.     int j;
  104.     for (j=0; j<[adds count]; j++) {
  105.         id objectToAdd = [adds objectAt:j];
  106.         if (level >= 0) {
  107.             if ([objectToAdd respondsTo:@selector(setDrawingLevel:)])
  108.                     [objectToAdd setDrawingLevel:level];
  109.             if ([objectToAdd respondsTo:@selector(setStage:)])
  110.                     [objectToAdd setStage:self];
  111.         }
  112.         [theList addObject:objectToAdd];
  113.     }
  114.     for (j=0; j<[removes count]; j++) {
  115.         id anActor = [removes objectAt:j];
  116.         [theList removeObject:anActor];
  117.         [stageManager addDeadActor:anActor];
  118.         // if not using a manager, free the object...
  119.         if (!stageManager) [anActor free];
  120.     }
  121.     return self;
  122. }
  123.  
  124. - doAddsAndRemoves
  125. {    // _now_ it can take effect (actors at all levels and collision groups
  126.     int i;
  127.     for (i=0; i<=GK_ACTOR_TYPES; i++) {
  128.         [self _add:addActors[i] remove:removeActors[i] with:actors[i] level:i];
  129.     }
  130.     [self _add:addCollisionGroups remove:removeCollisionGroups
  131.             with:collisionGroups level:(-1)];
  132.     return self;
  133. }
  134.  
  135. - doOneFrame
  136. {
  137.     [self calculateMoves];
  138.     [self calculateCollisions];
  139.     if ([self doRender]) [self render];
  140.     [self doAddsAndRemoves];
  141.     return self;
  142. }
  143.  
  144. - (BOOL)doRender { return YES; }
  145.  
  146. - calculateMoves
  147. {
  148.     int i;
  149.     for (i=0; i<=GK_ACTOR_TYPES; i++) {
  150.         [actors[i] makeObjectsPerform:@selector(move:) with:self];
  151.     }
  152.     return self;
  153. }
  154.  
  155. - calculateCollisions
  156. {
  157.     [collisionGroups makeObjectsPerform:@selector(calculateCollisions:)
  158.             with:self];
  159.     return self;
  160. }
  161.  
  162. - render
  163. {
  164.     register int i, j, k, t, lastLevel = 0; // lastLevel is the number of the
  165.     // next lower buffer level.  If a buffer doesn't exists, this allows us
  166.     // to skip it and use the next lowest (existing) buffer level.
  167.     // The actors will only move if the GameView is in the normal state
  168.     // and unpaused.  They can still advance the render state machine, though.
  169.     BOOL shouldMove = ((![drawingBuffers[GK_SCREEN_BUFFER] isPaused]) &&
  170.             ([drawingBuffers[GK_SCREEN_BUFFER] realGameState] == NORMALSTATE));
  171.     NXPoint offset;
  172.     [drawingBuffers[GK_SCREEN_BUFFER] getOffset:&offset];
  173.     // Loop through each buffer, allowing changes to propagate from
  174.     // the lowest to the highest buffer
  175.     for (i=1; i<GK_BUFFER_TYPES; i++) {
  176.         // Make sure that this buffer level exists; if not, we skip to the
  177.         // next level and push all actors in this level up to the next level.
  178.         if (drawingBuffers[i]) {
  179.             id thisDirtPile = nil;
  180.             // find the DirtPile for the next highest level.  (If a level
  181.             // doesn't have a buffer, we need to effectively skip it.)
  182.             for (k=i+1; k<GK_BUFFER_TYPES; k++) { // if on last buffer,
  183.                 // (top level) loop is skipped, and so thisDirtPile = nil
  184.                 if (dirtPiles[k]) {
  185.                     thisDirtPile = dirtPiles[k];
  186.                     break;
  187.             }    }
  188.             [drawingBuffers[i] lockFocus];
  189.             for (k=lastLevel+1; k<=i; k++) { // loop makes sure that any
  190.                 // actors on a level w/o a buffer still get drawn and erased,
  191.                 // but in the next higher buffer level.
  192.                 
  193.                 // erase everything on this level by marking it dirty in
  194.                 // the DirtPile for this level:  each actor sends it's
  195.                 // most recently drawn bounding box to the DirtPile.
  196.                 [actors[k] makeObjectsPerform:@selector(eraseInDirtPile:)
  197.                         with:dirtPiles[i]];
  198.             }
  199.             // Now, copy everything from the level below up to this level,
  200.             // using the DirtPile for efficiency.  This makes all erasing
  201.             // happen at once.
  202.             [dirtPiles[i] sendDirtTo:thisDirtPile]; // next level needs to
  203.             // know of all changes on lower levels.
  204.             [dirtPiles[i] doRedraw:drawingBuffers[lastLevel]]; // go back
  205.             // to the most recent buffer
  206.             for (k=lastLevel+1; k<=i; k++) { // loop makes sure that any
  207.                 // actors that are in a level w/o a buffer still get drawn,
  208.                 // but in the next highest buffer level.
  209.                 
  210.                 // Next draw anything that gets drawn at this level (any actors
  211.                 // that are here.
  212.                 t = [actors[k] count]; // faster than a message call each
  213.                 // time thru the loop; requires that the list not change
  214.                 // during the render, however!!!
  215.                 for (j=0; j<t; j++) { // loop ourselves to be
  216.                     // sure objects are called from #0 to highest; allows user
  217.                     // to add actors in the order they are expected to be drawn
  218.                     // (or sort the actors' drawing order)
  219.                     [[actors[k] objectAt:j] renderAt:&offset
  220.                             move:shouldMove withDirtPile:thisDirtPile];
  221.             }    }
  222.             [drawingBuffers[i] unlockFocus];
  223.             lastLevel = i;
  224.     }    }
  225.     return self;
  226. }
  227.  
  228. @end
  229.